﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SedCup.Code.Model
{
    public class Neighbour
    {
        /// <summary>
        /// Visszaadja az összes szomszédot!
        /// </summary>
        /// <param name="coordinate"></param>
        /// <param name="mapSize"></param>
        /// <returns></returns>
        public static List<int> getAllNeighbours(int coordinate, int mapSize)
        {
            List<int> list = new List<int>();
            int width = (coordinate % mapSize);
            int height = (coordinate / mapSize) + 1;

            if (width == 0)
            {
                width = mapSize;
                height--;
            }

            if (width - 1 > 0 && width <= mapSize)
            {
                list.Add(coordinate - 1);
            }
            if (width > 0 && width + 1 <= mapSize)
            {
                list.Add(coordinate + 1);
            }
            if (height - 1 > 0 && height <= mapSize)
            {
                list.Add(coordinate - mapSize);
            }
            if (height > 0 && height + 1 <= mapSize)
            {
                list.Add(coordinate + mapSize);
            }

            return list;
        }

        public static int profitFromTask(Dictionary<int, int> distances, Task task, int turn, int salary)
        {
            int timeToFinish = task.duration + distances[task.coordinate];

            if ((49 - turn) < timeToFinish)
            {
                return 0;
            }

            int totalSalary = (((timeToFinish / 5) + (((timeToFinish % 5) > 0) ? 1 : 0))) * (salary);

            return task.profit - totalSalary;
        }

        public static List<int> getNeighbours(int coordinate, int mapSize, Dictionary<int, List<int>> roadBlocks)
        {
            List<int> rvResult = getAllNeighbours(coordinate, mapSize);

            if (roadBlocks.ContainsKey(coordinate))
            {
                foreach (int element in roadBlocks[coordinate])
                {
                    rvResult.Remove(element);
                }
            }

            foreach (int element in getAllNeighbours(coordinate, mapSize))
            {
                if (roadBlocks.ContainsKey(element))
                {
                    if (roadBlocks[element].Contains(coordinate))
                    {
                        rvResult.Remove(element);
                    }
                }
            }

            return rvResult;
        }

        public static int getShortestRoadStep(int position, int mapSize, Dictionary<int, List<int>> roadBlocks, int target)
        {
            List<int> visited = new List<int>() { position };
            Stack<int> toVisit = new Stack<int>();
            Dictionary<int, int> parents = new Dictionary<int, int>();
            int steps = 1;

            foreach (int element in getNeighbours(position, mapSize, roadBlocks))
            {
                toVisit.Push(element);
                visited.Add(element);
                parents[element] = position;
            }

            while (visited.Count != (mapSize * mapSize))
            {
                int actualNode = toVisit.Pop();

                foreach (int element in getNeighbours(actualNode, mapSize, roadBlocks))
                {
                    if (!visited.Contains(element))
                    {
                        visited.Add(element);
                        toVisit.Push(element);
                        parents[element] = actualNode;
                    }
                }

                steps++;
            }

            int prev = parents[target];
            int prevprev = target;

            while (prev != position)
            {
                prevprev = prev;
                prev = parents[prev];
            }

            return prevprev;
        }

        public static Dictionary<int, int> determineAllDistancesFromPosition(int position, int mapSize, Dictionary<int, List<int>> roadBlocks) 
        {
            Dictionary<int, int> rvResult = new Dictionary<int, int>();
            int[] distances = new int[mapSize * mapSize + 1];
            distances[position] = 0;

            List<int> visited = new List<int>() { position };
            Stack<int> toVisit = new Stack<int>();

            int steps = 1;

            foreach (int element in getNeighbours(position, mapSize, roadBlocks)) {
                toVisit.Push(element);
                visited.Add(element);
                distances[element] = 1;
                rvResult[element] = distances[element];
            }

            while (visited.Count != (mapSize * mapSize))
            {
                int actualNode = toVisit.Pop();

                foreach (int element in getNeighbours(actualNode, mapSize, roadBlocks))
                {
                    if (!visited.Contains(element))
                    {
                        visited.Add(element);
                        toVisit.Push(element);
                        distances[element] = distances[actualNode] + 1;
                        rvResult[element] = distances[element];
                    }
                }

                steps++;
            }

            return rvResult;
        }
    }
}
